package main

import (
	"fmt"
	"interfaces/mock"
	"interfaces/real"
	"time"
)

/**
	Go语言规定，只要实现了接口里面的方法，就是该接口的实现类

	接口变量里面有什么？
	实现者的类型 和 实现者的指针

	接口变量自带指针
	接口变量同样采用值传递，几乎不需要使用接口的指针
	指针接收者实现只能以指针方式使用；值接收者都可以用

 */

// 声明一个 关于 Get 接口类型
type Retriever interface {
	// Get方法
	// 一个未实现的方法
	Get(url string) string
}

// 声明一个 关于 Post 接口
type Poster interface {
	// Post方法
	Post(url string, form map[string]string) string
}


func download(r Retriever) string {
	return r.Get("http://www.baidu.com")
}

func post(poster Poster)  {
	poster.Post("http://www.baidu.com", map[string]string{
		"name":"ccmouse",
		"course":"golang",
	})
}

// 接口组合
// 把 Retriever 和 Poster 组合起来
type RetrieverPoster interface {
	Retriever
	Poster
}

// 我这个函数，既可以调用 Retriever 的方法 也可以 Poster 的方法
func session(s RetrieverPoster) string {
	s.Post("http://www.baidu.com", map[string]string{
		"name":"ccmouse",
		"course":"golang",
	})

	return s.Get("http://www.baidu.com")
}

func main() {
	// 声明接口类型，但不分配内存
	var r Retriever
	// 获取 一个实现类，并赋值给 r
	// 因为 mock.Retriever 实现了 Retriever 接口里的方法，所以他就是一个实现类
	// 这里相当于就是把 mock.Retriever 值复制了一份，然后赋值给 r
	r = mock.Retriever{"这是一个百度网页"}

	// 输出是什么类型，也就是实现类型，以及值
	fmt.Printf("%T %v\n",r ,r)

	// 什么接口类型, 但不分配内存
	var rb Retriever
	// 实现类
	// 不建议使用接口指针，因为本身就自带了指针, 可以直接用指针
	rb = &real.Retriever{
		UserAgent: "Mozilla/5.0",
		TimeOut: time.Minute,
	}

	// 输出是什么类型，也就是实现类型，以及值
	fmt.Printf("%T %v\n",rb ,rb)

	//fmt.Println(download(r))
	//fmt.Println(download(rb))

	// 判断是什么类型
	inspect(rb)

	// 类型断言
	// 如果是指针就要用指针， 普通的就直接用，比如：mock.Retriever
	realRetriever, ok := r.(*real.Retriever)
	if ok {
		fmt.Println(realRetriever.TimeOut)
	} else {
		fmt.Println("这不是 mock.Retriever 类型")
	}


}

// 判断是什么类型
func inspect(r Retriever)  {

	// 判断是什么样的类型
	switch v := r.(type) {
	case mock.Retriever:
		fmt.Println("Contents: ", v.Contents)
	case *real.Retriever:
		fmt.Println("UserAgent: ", v.UserAgent)

	}
}
